<template>
  <div>
    <div id="container"></div>
  </div>
</template>

<script>
import * as THREE from 'three'
import gsap from 'gsap'
import * as dat from 'dat.gui'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
export default {
  components: {},
  data() {
    return {
      properties: {
        rotationSpeed: {
          name: 'rotationSpeed',
          value: 0.02,
          min: 0,
          max: 0.5,
          step: 0.01,
        },
        bouncingSpeed: {
          name: 'bouncingSpeed',
          value: 0.03,
          min: 0,
          max: 0.5,
          step: 0.01,
        },
        scalingSpeed: {
          name: 'scalingSpeed',
          value: 0.03,
          min: 0,
          max: 0.5,
          step: 0.01,
        },
      },
      cube: null,
      sphere: null,
      cylinder: null,
      step: 0,
      scalingStep: 0,
      camera: null,
      scene: null,
      renderer: null,
      controls: null,
      axes: null,
      cylinder_params: {
        top_r: 2, //上半径
        bottom_r: 2, //下半径
        height: 10, //高度
        color: '#fff000', //颜色
        x: 0,
        y: 5,
        z: 0,
      },
      gui: null,
    }
  },
  mounted() {
    this.init()
  },
  methods: {
    formatTooltip(val) {
      return val
    },
    // 初始化
    init() {
      this.createScene() // 创建场景
      this.createMeshs() // 创建网格对象
      this.createLight() // 创建光源
      this.createCamera() // 创建相机
      this.createRender() // 创建渲染器
      this.createControls() // 创建控件对象
      this.createAxisHelper() // 添加坐标轴
      this.render() // 渲染
      this.watchWindowSize() // 监听窗口大小
      this.watchFullScreen() //监听全屏事件
      this.creatGui() // 创建gui
    },
    //创建gui
    creatGui() {
      this.gui = new dat.GUI()
      //修改位置
      this.gui
        .add(this.cylinder.position, 'x')
        .min(0)
        .max(10)
        .step(0.1)
        .name('x轴')
        .onChange((value) => {
          console.log('当前x', value)
        })
        .onFinishChange((value) => {
          console.log('停止', value)
        })
      //修改颜色
      const params = {
        color: '#fff000',
        fn: () => {
          gsap.to(this.cylinder.position, {
            x: 20,
            duration: 2,
            yoyo: true,
            repeat: -1,
          })
        },
      }
      this.gui.addColor(params, 'color').onChange((value) => {
        this.cylinder.material.color.set(value)
      })
      //添加选项
      this.gui.add(this.cylinder, 'visible').name('是否显示')
      //设置按钮
      this.gui.add(params, 'fn').name('往返运动')
      //显示线框
      this.gui.add(this.cylinder.material, 'wireframe')
    },
    //创建坐标轴
    createAxisHelper() {
      const axesHelper = new THREE.AxesHelper(1000)
      this.scene.add(axesHelper)
    },
    // 创建场景
    createScene() {
      this.scene = new THREE.Scene()
    },

    // 创建光源
    createLight() {
      // 添加聚光灯
      const spotLight = new THREE.SpotLight(0xffffff)
      spotLight.position.set(-50, 80, 0)
      spotLight.castShadow = true
      this.scene.add(spotLight) // 聚光灯添加到场景中
      // 环境光
      const ambientLight = new THREE.AmbientLight(0x0c0c0c)
      this.scene.add(ambientLight)
    },
    // 创建相机
    createCamera() {
      const element = document.getElementById('container')
      const width = element.clientWidth // 窗口宽度
      const height = element.clientHeight // 窗口高度
      const k = width / height // 窗口宽高比
      // PerspectiveCamera( fov, aspect, near, far )
      this.camera = new THREE.PerspectiveCamera(40, k, 0.1, 10000)

      this.camera.position.set(80, 80, 80) // 设置相机位置
      //   this.camera.lookAt(new THREE.Vector3(5, 10, 0)) // 设置相机方向
      this.scene.add(this.camera)
    },
    // 创建渲染器
    createRender() {
      const element = document.getElementById('container')
      this.renderer = new THREE.WebGLRenderer()
      this.renderer.setSize(element.clientWidth, element.clientHeight) // 设置渲染区域尺寸
      this.renderer.setClearColor(0x3f3f3f, 1) // 设置背景颜色
      element.appendChild(this.renderer.domElement)
    },

    // 创建网格对象
    createMeshs() {
      // 创建底板并添加到场景
      const planeGeometry = new THREE.PlaneGeometry(100, 100, 1, 1)
      const planeMaterial = new THREE.MeshLambertMaterial({ color: 0xcccccc })
      const plane = new THREE.Mesh(planeGeometry, planeMaterial)
      plane.rotation.x = -0.5 * Math.PI
      plane.position.x = 0
      plane.position.y = -5
      plane.position.z = 0
      this.scene.add(plane)

      const cylinderGeometry = new THREE.CylinderGeometry(
        this.cylinder_params.top_r,
        this.cylinder_params.bottom_r,
        this.cylinder_params.height
      )
      const cylinderMaterial = new THREE.MeshLambertMaterial({
        color: this.cylinder_params.color,
      })
      this.cylinder = new THREE.Mesh(cylinderGeometry, cylinderMaterial)
      this.cylinder.position.set(
        this.cylinder_params.x,
        this.cylinder_params.y,
        this.cylinder_params.z
      )
      this.scene.add(this.cylinder)
      console.log(this.cylinder)
    },
    //重新渲染
    redraw() {
      this.scene.remove(this.cylinder)
      this.createMeshs()
    },

    render() {
      this.controls.update()
      this.renderer.render(this.scene, this.camera)
      requestAnimationFrame(this.render)
    },
    // 创建控件对象
    createControls() {
      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
      //设置控制器阻尼,必须在动画循环里面调用.update()
      this.controls.enableDamping = true
    },
    //监听窗口尺寸变化
    watchWindowSize() {
      let that = this
      window.addEventListener('resize', () => {
        that.updatePage()
      })
    },
    //更新
    updatePage() {
      //更新摄像头
      this.camera.aspect = window.innerWidth / window.innerHeight
      //更新摄像机投影矩阵
      this.camera.updateProjectionMatrix()
      //更新渲染器
      this.renderer.setSize(window.innerWidth, window.innerHeight)
      //更新像素比例
      this.renderer.setPixelRatio(window.devicePixelRatio)
    },
    //监听全屏事件
    watchFullScreen() {
      let that = this
      window.addEventListener('dblclick', () => {
        //全屏操作
        const fullScreenElement = document.fullscreenElement
        if (!fullScreenElement) {
          //进入全屏
          that.renderer.domElement.requestFullscreen()
        } else {
          //退出全屏
          document.exitFullscreen()
        }
      })
    },
  },
}
</script>

<style>
#container {
  position: absolute;
  width: 100%;
  height: 100%;
}
</style>
